/*
2-SAT问题:
有n个人，0，1是一组的；2，3是一组的；....；n-2，n-1是一组的。有m个限制条件，每个限制条件由a，b组成，表示a和b是不能相处的。
现在要从每组中选一个人出来构成一个团体，并且任意2个人都是能相处的。 
x   1 (~x->x)
    0 (x->~x)
x&y 1 (~x->x)^(~y->y)
    0 (x->~y)^(y->~x)
x|y 1 (~x->y)^(~y->x)
    0 (x->~x)^(y->~y)
x^y 1 (x->~y)^(y->~x)^(~x->y)^(~y->x)
    0 (x->y)^(~y->~x)^(~x->~y)^(y->x)
构图时，根据条件找可以确定关系的形如A->B这样的关系式
i表示i取1，~i表示i取0
poj 3678 有些边不用建，为什么
i AND j =1    ~i->i, ～j->j, i->j, j->i,后面两个关系式构成一个环，i,j在同一强连通分量中，可以免去

i AND j = 0   i->~i, j->~j 而~i推不出j为0还是1

i OR   j =1    ~i->j, ~j->i

i OR   J =0    i->~i,  j->~j, ~j->~i, ~i->~j 又有环，可以省略

i XOR j =1    i->~j,  j->~i,  ~i->j,  ~j->i

i XOR j =0    i->j,  j->i,  ~i->~j, ~j->~i   又构成两个环
*/
#define maxn  1030
//poj 3648
struct node
{
	int x,y;
	node(){}
	node(int aa,int bb)
	{x=aa; y=bb;}
};
char ch[100];
vector<node>vc;
bool operator<(const node &a,const node &b)
{
	return a.x<b.x;
}
/*************2-sat模板*********************/
template<int maxv,int maxe>
struct SAT
{
    int first[maxv],next[maxe],E[maxe],M;
    int all;   //N为点数， 总共的点，也就是乘以2后的点
    int dfn[maxv],low[maxv],sta[maxv],belong[maxv],bcnt,dindex,top,instack[maxv],op[maxv];  //缩点是0到bcnt-1
        void initop(int len)//构造正反对，并确定怎么标号
        {
           all=len;
           int nn=len/2;
           for(int i=0; i<nn; i++)//0到n-1的范围
            {
                op[i]=i+nn;
                op[i+nn]=i;
            }
        }
        void init()//初始化边
        {
            M=-1;
            memset(first,-1,sizeof(first));
        }
        void insert(int a,int b)
        {
            M++;
            next[M]=first[a];
            first[a]=M;
            E[M]=b;
        }
  /*函数build是对原图初始化(根据实际输入情况做相应的更改) */
        void   build()//建边这个地方可能需要随时修改
        {
            int i;
            insert(op[0],0);
            insert(n,op[n]);
	
           	for(i=1; i<n; i++)
           	{
           		insert(i,op[i+n]);
           		insert(op[i+n],i);
           		insert(i+n,op[i]);
           		insert(op[i],i+n);
           	}
            int x,p,q,z;
			char y;
			for(i=0; i<m ;i++)
			{
				scanf("%s",ch);
				sscanf(ch,"%d%c",&x,&y);
				if(y=='h') x=x+n;
				scanf("%s",ch);
				sscanf(ch,"%d%c",&z,&y);
				if(y=='h')z=z+n;
				insert(op[z],x);
				insert(op[x],z);	
			}
           
        }

        void tarjan(int u)
        {
            int e,v;
            dfn[u]=low[u]=++dindex;
            instack[u]=1;
            sta[++top]=u;
            for(e=first[u]; e!=-1; e=next[e])
            {
                v=E[e];
                if(!dfn[v])
                {
                    tarjan(v);
                    if(low[v]<low[u])
                        low[u]=low[v];
                }
                else if(instack[v]&& dfn[v]<low[u])
                    low[u]=dfn[v];
            }
            if(dfn[u]==low[u])
            {
                do{
                    v=sta[top--];
                    instack[v]=0;
                    belong[v]=bcnt;
                }while(v!=u);
                  bcnt++;
            }
        }
        bool judge()
        {
            for(int i=0; i<all; i++)
                if(belong[i]==belong[op[i]])
                    return false;
            return true;
        }
        int   solve()
        {
            int i;
            memset(dfn,0,sizeof(dfn));
            top=bcnt=dindex=0;
            for( i=0; i<all; i++)
                if(!dfn[i])
                    tarjan(i);
  /*统计每个强连通分量都包含哪些点，为后面求可行方案做准备。如果不求可行解，可注释掉。*/
            for(i=0; i<=all; i++)
            	contain[i].clear();
			for(i=0; i<=bcnt; i++)
            	tree[i].clear();
            for(i=0; i<all; i++)
            {
            	contain[belong[i]].pb(i);
            }
   /*******上面的那一段是为了有打印一组可行解所需要的************/       
            if(judge())
            {
            	getoneanswer();
                return 1;
            }
            else return 0;
        }
/********************上面是判断*************************************/
/********************下面是输出一组可行解******************/       
		 int cnt;//拓扑排序用
      	vector<int> tree[maxv];	//有向无环图的边连接情况(新图) 
		vector<int> contain[maxv];	//新图中每个点都包含原图中的哪些点 
        void getoneanswer()
		{
			buildGraph();
			TopologicalSort();
			color();
			tagAnswer();
			printAnswer();
		}
/*函数buildGraph把每个强连通分量作为一个点，重新构图。(缩点，得到的是一个有向无环图) 
用的是链接表的形式，可能有很多重边。可以加一些预处理消除重边。 */
        void buildGraph()
        {
        	int i,fu,fv,v,e;
        	for (i=0;i<bcnt;i++)
				tree[i].clear();
			for(i=0; i<all; i++)
				for(e=first[i]; e!=-1; e=next[e])
				{
					fu=belong[i];
					fv=belong[E[e]];
					if(fu!=fv)
						tree[fv].pb(fu);
				}
        }
/*函数topologicalSort和tsDfs是对新图进行拓扑排序，排序后的结果存在low数组中 */
        void TopologicalSort()
        {
        	int i;
        	for(i=0; i<bcnt; i++)
        	{
        		dfn[i]=-1;
        		low[i]=-1;
        	}
        	int nn=bcnt;
			cnt=bcnt=0;
			for (i=0;i<nn;i++)
			{
				if (dfn[i]==-1)
					tsDfs(i);
			}
        }
		void tsDfs(int k)
		{
			int i,w;
			dfn[k]=cnt++;
			for (i=0;i<tree[k].size();i++)
			{
				w=tree[k][i];
				if (dfn[w]==-1)
				{
					tsDfs(w);
				} 
			}  
			low[bcnt++]=k;             
		}	
/*函数color和colorDfs是对新图进行着色，新图中着色为1的点组成一组可行解 */ 
		void color()
		{
			int i,a,b;
			for (i=0;i<bcnt;i++)
				dfn[i]=-1; 
			for (i=bcnt-1;i>=0;i--)
				if (dfn[low[i]]==-1) 
				{
	/*	新图中low[i]着色为1后，它的矛盾点应标记为2 */
					a=contain[low[i]][0];	//在原图中找一点属于强连通分量low[i]的点a，点a所属组的另一点b所属的强连通分量id[b]一定是low[i]矛盾点。 
					b=op[a];
					dfn[low[i]]=1;
					if (dfn[belong[b]]==-1)
						colorDfs(belong[b]);	//由于依赖关系，有id[b]能达的点都是low[i]的矛盾点 
				}
		}
   	  	void  colorDfs(int k)
		{
			int i,w;
			dfn[k]=2;
			for (i=0;i<tree[k].size();i++)
			{
				w=tree[k][i];
				if (dfn[w]==-1)
				{
				    colorDfs(w);
				} 
			}          
		}
   /*函数tagAnswer由新图对原图的点进行标记，得到原图的可行解 */   	
        void tagAnswer()
		{
			int i,j;
			for (i=0;i<all;i++)
				low[i]=-1;
			for (i=0;i<bcnt;i++)
				if (dfn[i]==1)//i为新图中可行解包含的点，那么原图中强连通分量属于i的点都是原图中可行解的点 
				{
					for (j=0;j<contain[i].size();j++)
						low[contain[i][j]]=1;
				}
		}
	/*函数printAnswer打印原图的可行解 
值得注意的是现在图上的一组解保存在low里面,low为1是一组可行解，low为2是一组可行解*/ 
		void printAnswer()//打印这要特别注意一下怎么改
		{//low为1是一组可行解，low为2是一组可行解
		//low是从0到n-1 标号的，对应建图时候的标号
			int now=low[0],i,j;
			for (i=1;i<all/2;i++)
			{
				if (low[i]==now)
				{
					if(i<all/4)
					{
						vc.pb(node(i,0));
					}
					else
					{
						vc.pb(node(i-all/4,1));
					}
				}
			}
		}
/********************上面是输出一组可行解******************/   
};
SAT<1100,160000> sat;//第一个是点，第二个是边
/*************2-sat模板*********************/
int main()
{
     #ifndef ONLINE_JUDGE
        freopen("in","r",stdin);
    #endif
    int t,i,j,k;
    while(scanf("%d%d",&n,&m),n||m)
    {
    	vc.clear();
  /*********2-sat模板**************************/
    	sat.init();
    	sat.initop(n*4); //传入总共的点，也就是乘以2后的点
    	sat.build();
  /*********2-sat模板**************************/
 /*********2-sat模板**************************/
    	if(sat.solve()==0)
 /*********2-sat模板**************************/
        {
			puts("bad luck");
        }
        else
        {
        	sort(vc.begin(),vc.end());
        	for(i=0; i<sz(vc)-1; i++)
        	{
        		if(vc[i].y==0)
	        		printf("%dw ",vc[i].x);
				else
					printf("%dh ",vc[i].x);
        	}
        	if(i<sz(vc))
        	{
        		if(vc[i].y==0)
	        		printf("%dw\n",vc[i].x);
				else
					printf("%dh\n",vc[i].x);
        	}
        }
    }
}
